Skip to content
kennytilton  /   web-mx-workshop  /  
  • Unwatch 1

    Notifications

    Get push notifications on iOS or Android.
  • Fork 0 Fork your own copy of kennytilton/web-mx-workshop

Editing The Evolution of a Web MX Inspector

Someone has edited the wiki since you started. Please reload this page and re-apply your changes.

Our first workshop will produce a series of tagged commits evolving a live inspector for Web/MX apps. We will use the Web/MX Quickstart as our target, so we have something to inspect.

The drill

I will:

  • work for a day or so, commenting heavily;
  • reach some milestone;
  • rebase commits made during the day so one commit has everything;
  • tag that commit with a helpful name for the milestone; and
  • push.

Folks can then git diff before and after to see the work side-by-side.

And now on to the first tag.

Tag Zero: qs-cleanup-with-css-inlined

Our first tag will not actually tackle the inspector. We just wanted to get the ball rolling, and cleaning up the Quickstart main controller was a ripe target. It happens also to demonstrate the easy refactoring possible when widgets handle state communication themselves. So on with the cleanup.

The Web/MX Quickstart (QS) was never meant to be anything other than a throwaway; we just needed it to present the dozen or so QS lessons. No serious evolution was anticipated, so it is a bit of a mess.

Aside from that, one cleanup we have in mind is getting copious in-line CSS out of the way.

Ergo, two main goals to get the source mess under control:

  1. move in-line CSS literals into CLJS functions, in part to get them out of the way, but also to start a conversation about separate CSS not necessarily being effective. For one, that totally breaks the co-location win. For another, Web/MX supports dynamic :style formulas, which cannot live in .css files, so CSS will end up partly in formulas and partly in CSS files, combined by HTML class attributes. CLJS functional composition is more powerful and predictable than CSS class manipulation, so unless we are doing CSS animations, we will stay away from class-based CSS authoring. Over time. We have some classes now and can leave them until we really dive into CLJS->CSS; and
  2. just break out code into functions. Note that in some cases this will be HTML chunks, and in others individual cell formulas.

Changes made

  • Break out the router starter as separate function 'qs-router-starter', and
  • ... break out the app-wide key handler (for lesson navigation) as qs-keydown-handler.
  • Move most CSS into functions in core/style.cljs.
  • DRY a reusable 'text-block' component for sequences of text paragraphs.
  • Break out the toolbar and right-side entire lesson display into componentsin a new core.widget NS.
  • Move the glossary display logic into the core.glossary NS.
  • Move the global lessons array hardcode into the lessons NS.

Tag One: hello-inspector

Now we start on the inspector proper.

Objective

Our first goal is to just have some user gesture pop open a new DIV right alongside the QS app, and display as much of the QS structure as possible in a day's effort.

Ideally we would open a new browser tab and workout communication between the two, but that will take some head-scratching, and again we want to dig into w/mx leaning more than we want to get sophisticated with browser tech.

So we will cheat and modify index.html to have a second "inspector" placeholder DIV alongside the "app" DIV, and when the "open inspector" gesture is received, populate the "inspector" DIV with structure mirroring the "app" structure, but with little inspector widgets.

This, btw, will give w/mx noobs a feel for how w/mx code initially connects with the DOM. Speaking of which:

(defn main [mx-builder]
  (let [app (gdom/getElement "app")
        app-matrix (mx-builder)
        app-dom (tag-dom-create app-matrix)]
    (reset! matrix app-matrix)
    (set! (.-innerHTML app) nil)
    (gdom/appendChild app app-dom)

    (when-let [router-starter (mget? app-matrix :router-starter)]
      (router-starter))))

(main #(quick-start "Web/MX&trade;<br>Quick Start"
         (lesson/qs-lessons)))

The above main function gets kicked off by the top-level form below it, on page load.

We just need to write a wmx-inspector function to generate the initial DOM for the inspector, then emulate the code above to get the inspector loaded.

Step #1 Trap option-cmd-x First extend the raw index.html:

<body>
<div id="root"
     style="display:flex;flex-direction:row">
    <div id="app"></div>
    <div id="inspector"></div>
</div>
<script src="../cljs-out/qs-main.js"></script>
</body>

...then add this to the QS window event handler.

(let [key-evt (wmx/jso-select-keys evt
                [:type :keyCode :metaKey :altKey :shiftKey :ctrlKey])]
  ;; step #1: parse and recognize option-cmd-X keychord
  (case key-evt
    {:type "keydown" :keyCode 88
     :metaKey true :altKey true
     :shiftKey false :ctrlKey false}
    (i/inspector-install)
    (do #_ (prn :unknown-key-evt!!! key-evt)))
  nil)

Step #2 Find the new "inspector" tag and modify First just see if we can get a dummy span installed in the right place.

(defn inspector-install []
  (let [app (gdom/getElement "inspector")]
    (set! (.-innerHTML app) nil)
    (gdom/appendChild app
      (tag-dom-create
        (span "Your inspector here!"))))

Step #3 Knock together a primitive inspector hard-coded to display the MX under the "app" DIV just three levels deep, with just a spab showing the MX :name, or :tag if unnamed.

(defn mxi-md-view [md depth]
  (when (pos? depth)
    (cond
      (string? md) (span md)
      (md-ref? md) (do
                     (div {}
                       {:md md}
                       (span (mget? md :name
                               (mget? md :tag "noname")))
                       ;; ^^^ no tag should not occur, wmx builds that in
                       (div {:style {:padding-left "1em"}} {}
                         (mapv #(mxi-md-view % (dec depth)) (mget? md :kids)))))
      :else (span "not string or md"))))

(defn inspector-toolbar []
  (div {:style {:justify-content :space-between
                :margin "2em"
                :gap "1em"
                :display :flex}}
    (span "inspector toolbar")
    (span {:onclick (fn [evt]
                      ; todo break this out as inspector-uninstall then make keychord a toggle
                      (let [mxi (fasc :mxi (evt-md evt))
                            dom (gdom/getElement "inspector")]
                        (md-quiesce mxi)
                        (set! (.-innerHTML dom) nil)))}
      ;; todo find a nice "close" icon?
      "[X]")))

Results

Run the app, make the window twice as wide as the content shown, then hit the key chord option-cmd-x. We should see:

    inspector toolbar   [X]

:quick-start
  div
    span
    i
    span
    div
  div
    div

Click the [x] to clear the inspector.

Editing The Evolution of a Web MX Inspector · kennytilton/web-mx-workshop Wiki